home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / UpdateManager / ReleaseNotesViewer.py < prev    next >
Text File  |  2009-11-02  |  7KB  |  190 lines

  1. # ReleaseNotesViewer.py
  2. #  
  3. #  Copyright (c) 2006 Sebastian Heinlein
  4. #  
  5. #  Author: Sebastian Heinlein <sebastian.heinlein@web.de>
  6. #
  7. #  This modul provides an inheritance of the gtk.TextView that is 
  8. #  aware of http URLs and allows to open them in a browser.
  9. #  It is based on the pygtk-demo "hypertext".
  10. #  This program is free software; you can redistribute it and/or 
  11. #  modify it under the terms of the GNU General Public License as 
  12. #  published by the Free Software Foundation; either version 2 of the
  13. #  License, or (at your option) any later version.
  14. #  This program is distributed in the hope that it will be useful,
  15. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. #  GNU General Public License for more details.
  18. #  You should have received a copy of the GNU General Public License
  19. #  along with this program; if not, write to the Free Software
  20. #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  21. #  USA
  22.  
  23.  
  24. import pygtk
  25. import gtk
  26. import pango
  27. import subprocess
  28. import os
  29.  
  30. class ReleaseNotesViewer(gtk.TextView):
  31.     def __init__(self, notes):
  32.         """Init the ReleaseNotesViewer as an Inheritance of the gtk.TextView.
  33.            Load the notes into the buffer and make links clickable"""
  34.         # init the parent
  35.         gtk.TextView.__init__(self)
  36.         # global hovering over link state
  37.         self.hovering = False
  38.         self.first = True
  39.         # setup the buffer and signals
  40.         self.set_property("editable", False)
  41.         self.set_cursor_visible(False)
  42.         self.buffer = gtk.TextBuffer()
  43.         self.set_buffer(self.buffer)
  44.         self.buffer.set_text(notes)
  45.         self.connect("event-after", self.event_after)
  46.         self.connect("motion-notify-event", self.motion_notify_event)
  47.         self.connect("visibility-notify-event", self.visibility_notify_event)
  48.         # search for links in the notes and make them clickable
  49.         self.search_links()
  50.  
  51.     def tag_link(self, start, end, url):
  52.         """Apply the tag that marks links to the specified buffer selection"""
  53.         tag = self.buffer.create_tag(None, foreground="blue",
  54.                                      underline=pango.UNDERLINE_SINGLE)
  55.         tag.set_data("url", url)
  56.         self.buffer.apply_tag(tag , start, end)
  57.  
  58.     def search_links(self):
  59.         """Search for http URLs in the buffer and call the tag_link method
  60.            for each one to tag them as links"""
  61.         # start at the beginning of the buffer
  62.         iter = self.buffer.get_iter_at_offset(0)
  63.         while 1:
  64.             # search for the next URL in the buffer
  65.             ret = iter.forward_search("http://", gtk.TEXT_SEARCH_VISIBLE_ONLY,
  66.                                       None)
  67.             # if we reach the end break the loop
  68.             if not ret:
  69.                 break
  70.             # get the position of the protocol prefix
  71.             (match_start, match_end) = ret
  72.             match_tmp = match_end.copy()
  73.             while 1:
  74.                 # extend the selection to the complete URL
  75.                 if match_tmp.forward_char():
  76.                     text =  match_end.get_text(match_tmp)
  77.                     if text in (" ", ")", "]", "\n", "\t"):
  78.                         break
  79.                 else:
  80.                     break
  81.                 match_end = match_tmp.copy()
  82.             # call the tagging method for the complete URL
  83.             url = match_start.get_text(match_end)
  84.             self.tag_link(match_start, match_end, url)
  85.             # set the starting point for the next search
  86.             iter = match_end
  87.  
  88.     def event_after(self, text_view, event):
  89.         """callback for mouse click events"""
  90.         # we only react on left mouse clicks
  91.         if event.type != gtk.gdk.BUTTON_RELEASE:
  92.             return False
  93.         if event.button != 1:
  94.             return False
  95.  
  96.         # try to get a selection
  97.         try:
  98.             (start, end) = self.buffer.get_selection_bounds()
  99.         except ValueError:
  100.             pass
  101.         else:
  102.             if start.get_offset() != end.get_offset():
  103.                 return False
  104.  
  105.         # get the iter at the mouse position
  106.         (x, y) = self.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
  107.                                               int(event.x), int(event.y))
  108.         iter = self.get_iter_at_location(x, y)
  109.         
  110.         # call open_url if an URL is assigned to the iter
  111.         tags = iter.get_tags()
  112.         for tag in tags:
  113.             url = tag.get_data("url")
  114.             if url != "":
  115.                 self.open_url(url)
  116.                 break
  117.  
  118.     def open_url(self, url):
  119.         """Open the specified URL in a browser"""
  120.         # Find an appropiate browser
  121.         if os.path.exists("/usr/bin/exo-open"):
  122.             command = ["exo-open", url]
  123.         elif os.path.exists('usr/bin/gnome-open'):
  124.             command = ['gnome-open', url]
  125.         else:
  126.             command = ['x-www-browser', url]
  127.  
  128.         # Avoid to run the browser as user root
  129.         if os.getuid() == 0 and os.environ.has_key('SUDO_USER'):
  130.             command = ['sudo', '-u', os.environ['SUDO_USER']] + command
  131.  
  132.         subprocess.Popen(command)
  133.  
  134.     def motion_notify_event(self, text_view, event):
  135.         """callback for the mouse movement event, that calls the
  136.            check_hovering method with the mouse postition coordiantes"""
  137.         x, y = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
  138.                                                  int(event.x), int(event.y))
  139.         self.check_hovering(x, y)
  140.         self.window.get_pointer()
  141.         return False
  142.     
  143.     def visibility_notify_event(self, text_view, event):
  144.         """callback if the widgets gets visible (e.g. moves to the foreground)
  145.            that calls the check_hovering method with the mouse position
  146.            coordinates"""
  147.         (wx, wy, mod) = text_view.window.get_pointer()
  148.         (bx, by) = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, wx,
  149.                                                      wy)
  150.         self.check_hovering(bx, by)
  151.         return False
  152.  
  153.     def check_hovering(self, x, y):
  154.         """Check if the mouse is above a tagged link and if yes show
  155.            a hand cursor"""
  156.         _hovering = False
  157.         # get the iter at the mouse position
  158.         iter = self.get_iter_at_location(x, y)
  159.         
  160.         # set _hovering if the iter has the tag "url"
  161.         tags = iter.get_tags()
  162.         for tag in tags:
  163.             url = tag.get_data("url")
  164.             if url != "":
  165.                 _hovering = True
  166.                 break
  167.  
  168.         # change the global hovering state
  169.         if _hovering != self.hovering or self.first == True:
  170.             self.first = False
  171.             self.hovering = _hovering
  172.             # Set the appropriate cursur icon
  173.             if self.hovering:
  174.                 self.get_window(gtk.TEXT_WINDOW_TEXT).\
  175.                         set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
  176.             else:
  177.                 self.get_window(gtk.TEXT_WINDOW_TEXT).\
  178.                         set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
  179.  
  180. if __name__ == "__main__":
  181.     # some simple test code
  182.     win = gtk.Window()
  183.     rv = ReleaseNotesViewer(open("../DistUpgrade/ReleaseAnnouncement").read())
  184.     win.add(rv)
  185.     win.show_all()
  186.     gtk.main()
  187.